#!/usr/bin/python

import re
import sqlite3
import sys

HEADLINE_PATTERN = '\\par }{\\b\\f36\\fs24\\cf6\\insrsid9862507\\charrsid7426838 '
LINE_DIRECTION = re.compile('^(A|B|Bx|C|D|E|F|H)\. (.+?)-(.+?)\.')

data = open(sys.argv[-2]).readlines()
data = '\n'.join(data).split(HEADLINE_PATTERN)

lines = [d for d in data if LINE_DIRECTION.match(d)]

def parse_line(input):
  result = [] # database rows
  
  input = input.split('\n')
  input.reverse()
  
  info = LINE_DIRECTION.match(input.pop())
  line, start, end = info.groups()
  if 'minutter' in end:
    return
  
  c1 = parse_constraint(input)
  input_test = input[:]
  c2 = parse_constraint(input_test)
  if c2:
    input = input_test
  if 'Frederikssund' in end:
    c3 = parse_constraint(input)
  else:
    c3 = None
  
  input_test = input[:]
  e = parse_exceptions(input_test)
  if e:
    input = input_test
  set_premature_end_of_line = False
  
  line_b_extended = False
  if start == 'H\\\'f8je Taastrup' and end == 'Holte':
    e = { 'start': '0.11', 'to': 'Hiller\\\'f8d'}
    line_b_extended = True
  
  input_test = input[:]
  stops_at_all_after_latest = parse_stops_all(input_test)
  if stops_at_all_after_latest:
    input = input_test
  station = None
  after_central = False
  after_ballerup = False
  previous_minute = -1
  while len(input):
    station = get_station(input)
    info = re.compile('.*?charrsid7426838 (.+?): ([\d*,\sX]+)').match(station)
    if not info:
      continue
    
    station_name, trains = info.groups()
    after_central = after_central or station_name == 'K\\\'f8benhavn H'
    after_ballerup = after_ballerup or station_name == 'Ballerup'
    added_latest = False
    only_latest_stop = False
    for minute in trains.split(', '):
      if minute == 'X':
        if previous_minute > -1:
          minute = previous_minute
          only_latest_stop = True
        else:
          continue
      else:
        previous_minute = minute
      
      the_end = end
      if the_end == 'Ballerup/Frederikssund':
        if '*' in minute:
          the_end = 'Frederikssund'
        else:
          the_end = 'Ballerup'
      
      if after_ballerup and the_end == 'Ballerup':
        continue
      
      if station_name == the_end:
        continue
      
      item = [
        fix_encoding(station_name),
        line,
        fix_encoding(the_end),
        minute.replace('*', ''),
      ]
      
      # Handle trains that start from central, as well as from the start point of the line
      if not after_central:
        constraint = c1
      else:
        constraint = c2
      
      week = sat = sun = None
      if '*' in minute:
        if 'week_day' in constraint:
          week = constraint['week_day']
        else:
          week = constraint['week']
        if 'sat_day' in constraint:
          sat = constraint['sat_day']
        else:
          sat = constraint['sat']
      else:
        if 'week' in constraint:
          week = constraint['week']
        if 'sat' in constraint:
          sat = constraint['sat']
        if 'sun' in constraint:
          sun = constraint['sun']
      
      if e:
        item_exc = item[:]
        item_exc[2] = fix_encoding(e['to'])
        if stops_at_all_after_latest and only_latest_stop:
          if added_latest:
            continue
          
          added_latest = True
          
          if week and minute == week.split('-')[1]:
            result.append(constrain_item(item_exc[:], 1, e['start'] + '-' + minute))
          if sat and minute == sat.split('-')[1]:
            result.append(constrain_item(item_exc[:], 2, e['start'] + '-' + minute))
          if sun and minute == sun.split('-')[1]:
            result.append(constrain_item(item_exc[:], 3, e['start'] + '-' + minute))
        else:
          if e['to'] == station_name:
            set_premature_end_of_line = True
          if not set_premature_end_of_line:
            week_end = sat_end = sun_end = None
            if week:
              result.append(constrain_item(item_exc[:], 1, e['start'] + '-' + week.split('-')[1]))
              week = week.split('-')[0] + '-' + e['start']
            if sat:
              result.append(constrain_item(item_exc[:], 2, e['start'] + '-' + sat.split('-')[1]))
              sat = sat.split('-')[0] + '-' + e['start']
            if sun:
              result.append(constrain_item(item_exc[:], 3, e['start'] + '-' + sun.split('-')[1]))
              sun = sun.split('-')[0] + '-' + e['start']
          
            if line_b_extended:
              for extended_station in [('Birker\\\'f8d', '12'), ('Aller\\\'f8d', '17'), ('Hiller\\\'f8d', '25')]:
                item_exc[0] = fix_encoding(extended_station[0])
                item_exc[3] = extended_station[1]
                if week:
                  result.append(constrain_item(item_exc[:], 1, e['start'] + '-125'))
                if sat:
                  result.append(constrain_item(item_exc[:], 2, e['start'] + '-125'))
                if sun:
                  result.append(constrain_item(item_exc[:], 3, e['start'] + '-125'))
              
      if only_latest_stop:
        continue
      
      if week:
        result.append(constrain_item(item[:], 1, week))
      
      if sat:
        result.append(constrain_item(item[:], 2, sat))
      
      if sun:
        result.append(constrain_item(item[:], 3, sun))
  
  return result


def parse_constraint(input):
  constraint = input.pop()
  while not 'Fra' in constraint and len(input):
    constraint = input.pop()
  
  # normal
  result = re.compile('.*Fra (?P<from>.+?) til (?P<to>.+?): ma\.\-fr\.: (?P<week>.+?)\. ma\.\-fr\.\*: (?P<week_day>.+?)\. l..f8\.: (?P<sat>.+?)\. l..f8\.\*: (?P<sat_day>.+?)\. s..f8\. og hldg\.: (?P<sun>.+?)\.\}.*').match(constraint)
  if not result:
    # normal, no daytime on saturday
    result = re.compile('.*Fra (?P<from>.+?) til (?P<to>.+?): ma\.\-fr\.: (?P<week>.+?)\. ma\.\-fr\.\*: (?P<week_day>.+?)\. l..f8\.: (?P<sat>.+?)\. s..f8\. og hldg\.: (?P<sun>.+?)\.\}.*').match(constraint)
  if not result:
    # normal, no daytime at all
    result = re.compile('.*Fra (?P<from>.+?) til (?P<to>.+?): ma\.\-fr\.: (?P<week>.+?)\. l..f8\.: (?P<sat>.+?)\. s..f8\. og hldg\.: (?P<sun>.+?)\.\}.*').match(constraint)
  if not result:
    # just daytime
    result = re.compile('.*Fra (?P<from>.+?) til (?P<to>.+?): ma\.\-fr\.\*: (?P<week_day>.+?)\. l..f8\.\*: (?P<sat_day>.+?)\.\}.*').match(constraint)
  if not result:
    # an extra train
    result = re.compile('.*Fra (?P<from>.+?) til (?P<to>.+?): ma\.\-fr\.: (?P<morning>\d+\.\d+\-\d+\.\d+) - (?P<afternoon>\d+\.\d+\-\d+\.\d+)\..*').match(constraint)
  if result:
    return result.groupdict()


def parse_exceptions(input):
  if len(input) == 0:
    return
  
  while len(input) > 1 and not 'k\\\'f8rer kun til' in input[-1]:
    input.pop()
  
  info = re.compile('.*? (?P<start>\d+\.\d+).*? fra (?P<from>.+?) k..f8rer kun til (?P<to>.+?)(\.| og).*').match(input[-1])
  if not info:
    return None
  
  return info.groupdict()


def parse_stops_all(input):
  if len(input) == 0:
    return
  
  while len(input) > 0 and not ' standser ved alle stationer' in input[-1]:
    input.pop()
  
  return len(input) > 0

def get_station(input):
  station = input.pop()
  while len(input) and not re.compile('.*? (.+?):.*').match(station):
    station = input.pop()
  
  return station


def constrain_item(item, type, constraint):
  item.append(type)
  item.append(constraint.split('-')[0].replace('.', ''))
  item.append(constraint.split('-')[1].replace('.', ''))
  return item


def fix_encoding(s):
  s = unicode(s, 'ascii').replace('`e', 'e').replace(' (spor 13)', '')
  broken = re.compile(u'\\\'(..)').findall(s)
  for b in broken:
    s = s.replace(u'\\\'' + b, unicode(chr(int(b, 16)), 'latin-1'))
  return s

def update():
  table = [parse_line(l) for l in lines]
  table = filter(lambda item: item is not None, table)

  count = 0
  conn = sqlite3.connect(sys.argv[-1])
  c = conn.cursor()
  for line in table:
    for departure in line:
      c.execute("""insert into Departures values (?, ?, ?, ?, ?, ?, ?)""", departure)
      count += 1
  conn.commit()
  conn.close()

  print count

update()
# parse_line(lines[6])